/**
 * @date 2006-2-27 13:03:33
 *
 */
package org.nanhill.xmlro.sro.spring;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.nanhill.commons.http.HttpHeader;
import org.nanhill.commons.lang.ReflectCache;
import org.nanhill.commons.xml.XmlParseException;
import org.nanhill.xmlro.XmlroTransport;
import org.nanhill.xmlro.spring.AbstractXmlroControllerExporter;
import org.nanhill.xmlro.sro.SroTransport;
import org.nanhill.xmlro.sro.SroHelper;
import org.nanhill.xmlro.sro.obj.DifferCompTypeArray;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.WebContentGenerator;

/**
 * Xmlro Ajax Controller Exporter.
 * 
 * @author alin [xalinx at gmail dot com]
 * 
 */
public abstract class SroAbstractControllerExporter extends
		AbstractXmlroControllerExporter {
	/**
	 * Default sro agent.
	 */
	private static final XmlroTransport SRO_AGENT = new SroTransport();

	/*
	 * 
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		// set sro agent
		if (null == this.xmlroAgent) {
			this.xmlroAgent = SRO_AGENT;
		}
	}

	/**
	 * Process the incoming xmlro request and create a xmlro response.
	 * 
	 * @throws IOException
	 * @throws XmlParseException
	 * 
	 * @throws ServletException
	 */
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		try {
			// only support POST method
			if (!WebContentGenerator.METHOD_POST.equals(request.getMethod())) {
				throw new ServletException("Only supports POST http requests!");
			}
			Object serviceInstance = this.getCallService(request);
			Method method = this.getCallMethod(request, serviceInstance);
			// {{ receive the object from http request
			Object result = null;
			Type[] paramTypes = ReflectCache
					.getMethodParamTypeFocusClass(method);
			//xmlroAgent.setCharacterSet(request.getCharacterEncoding());
			Object[] params = null;
			// ignore no parameter method
			if (0 != paramTypes.length) {
				DifferCompTypeArray paramContainer = new DifferCompTypeArray();
				paramContainer.setCompTypes(paramTypes);
				xmlroAgent.receive(paramContainer, request.getInputStream());
				params = paramContainer.getCompValues();
			}
			result = method.invoke(serviceInstance, params);
			// }}
			// -- send return type of RPC method
			response.setContentType(HttpHeader.CONTENT_TYPE_HTML);
			xmlroAgent.send(result, response.getOutputStream());
		} catch (InvocationTargetException e) {
			e.printStackTrace();
			Map<String, String> map = new HashMap<String, String>();
			map.put(SroHelper.SRO_FAULT, "401");
			map.put("message", e.getCause().getMessage());
			map.put("detail", e.getMessage());
			xmlroAgent.send(map, response.getOutputStream());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Map<String, String> map = new HashMap<String, String>();
			map.put(SroHelper.SRO_FAULT, "400");
			map.put("message", e.toString());
			map.put("detail", e.getMessage());
			xmlroAgent.send(map, response.getOutputStream());
		}
		return null;
	}

}
